package com.suning.sawp.service.impl.bi;

import java.io.Closeable;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.LocalDate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.suning.framework.dal.client.DalClient;
import com.suning.istore.common.bi.ftp.AbstractPropertySetter;
import com.suning.istore.common.bi.ftp.DefaultLineMapper;
import com.suning.istore.common.bi.ftp.FTPSynService;
import com.suning.istore.common.bi.ftp.TodaySupplier;
import com.suning.istore.common.integration.BIDataCleanService;
import com.suning.istore.common.integration.SQLIterator;
import com.suning.istore.common.sims.ftp.SIMSFTPSynService;
import com.suning.istore.lang.BufferedAction.Action;
import com.suning.sawp.constants.ConfigConstants;
import com.suning.sawp.constants.ExportConstants;
import com.suning.sawp.intf.model.ModelCommodityBaseInfo;
import com.suning.sawp.intf.model.ModelCommodityClusterBean;
import com.suning.sawp.intf.model.ModelConstant;
import com.suning.sawp.intf.model.ModelFinanceListBean;
import com.suning.sawp.intf.model.ModelFinanceStorageProblemListBean;
import com.suning.sawp.intf.model.ModelManageDaoService;
import com.suning.sawp.intf.model.ModelValidityBean;
import com.suning.sawp.intf.store.StoreInfoService;
import com.suning.sawp.po.store.StoreInfo;
import com.suning.sawp.service.impl.bi.support.SimpleContextWithDefinition;
import com.suning.sawp.service.impl.model.ModelCommodityInfoServiceImpl;
import com.suning.sawp.service.util.DateUtils;
import com.suning.sawp.service.util.ExportFileUtil;
import com.suning.sawp.service.util.SCMConfigUtil;

public class BIModelServiceImpl implements BIModelService {

    private static final Logger LOGGER = LoggerFactory.getLogger(BIModelServiceImpl.class);

    /**
     * 主要考虑调以后分库分表的支持
     */
    @Autowired
    DalClient dalClient;

    @Autowired
    FTPSynService ftpSynService;

    @Autowired
    SIMSFTPSynService modelFinFtpService;

    @Autowired
    SIMSFTPSynService modelFinInitFtpService;

    @Autowired
    StoreInfoService storeInfoService;

    @Resource
    ModelCommodityInfoServiceImpl modelCommodityInfoService;
    @Resource
    ModelManageDaoService         modelManageDaoService;
    
    @Resource
    ExportFileUtil exportFileUtil;

    /**
     * 抽取数据的数据源
     */
    @Autowired
    @Qualifier("sawpjndi")
    DataSource dataSource;

    private Map<String, String> selectSqls;

    private static final Pattern STORE_PATTERN = Pattern.compile("^[J,K,L].*");

    private static final Map<String, String> STORE_MAP = new HashMap<String, String>() {
        private static final long serialVersionUID = 1L;

        {
            put("J", "7");
            put("K", "8");
            put("L", "9");
        }
    };

    public Map<String, String> getSelectSqls() {
        return selectSqls;
    }

    public void setSelectSqls(Map<String, String> selectSqls) {
        this.selectSqls = selectSqls;
    }

    @Override
    public void uploadModelList(String remoteDirectory, String date, String fileName, Integer limit)
            throws SQLException {
        final String lineSeparator = "|@|\n";
        // 默认上传到今天的文件目录
        final LocalDate localDate = new TodaySupplier(date).get();
        ftpSynService.uploadBIFile(remoteDirectory, fileName, localDate, lineSeparator,
                new SQLIterator(dataSource, selectSqls.get("uploadModelList")),
                new Function<Map<String, Object>, String>() {
                    @Override
                    public String apply(Map<String, Object> row) {
                        return Joiner.on("|$|").join(
                                Iterables.transform(row.entrySet(), new Function<Map.Entry<String, Object>, String>() {
                            @Override
                            public String apply(Entry<String, Object> input) {
                                // 默认直接处理成字符串
                                Object val = input.getValue();
                                if (null == val) {
                                    return "";
                                }
                                if ("commName".equals(input.getKey())) {
                                    return val.toString().replace("\n", "").replace("\r", "");
                                }
                                return val.toString();
                            }
                        }));
                    }
                }, limit == null ? -1 : limit);
    }

    @Override
    public void uploadSaleModelList(String remoteDirectory, String date, String fileName, Integer limit)
            throws SQLException {
        final String lineSeparator = "|@|\n";
        // 默认上传到今天的文件目录
        final LocalDate localDate = new TodaySupplier(date).get();
        ftpSynService.uploadBIFile(remoteDirectory, fileName, localDate, lineSeparator,
                new SQLIterator(dataSource, selectSqls.get("uploadSaleModelList")),
                new Function<Map<String, Object>, String>() {
                    @Override
                    public String apply(Map<String, Object> row) {
                        return Joiner.on("|$|").join(
                                Iterables.transform(row.entrySet(), new Function<Map.Entry<String, Object>, String>() {
                            @Override
                            public String apply(Entry<String, Object> input) {
                                // 默认直接处理成字符串
                                Object val = input.getValue();
                                if (null == val) {
                                    return "";
                                }
                                if ("commName".equals(input.getKey())) {
                                    return val.toString().replace("\n", "").replace("\r", "");
                                }
                                return val.toString();
                            }
                        }));
                    }
                }, limit == null ? -1 : limit);
    }

    @Override
    public void uploadModelCluster(String remoteDirectory, String date, String fileName, Integer limit)
            throws SQLException {
        final String lineSeparator = "|@|\n";
        // 默认上传到今天的文件目录
        final LocalDate localDate = new TodaySupplier(date).get();
        ftpSynService.uploadBIFile(remoteDirectory, fileName, localDate, lineSeparator,
                new SQLIterator(dataSource, selectSqls.get("uploadModelCluster")),
                new Function<Map<String, Object>, String>() {
                    @Override
                    public String apply(Map<String, Object> row) {
                        return Joiner.on("|$|").join(
                                Iterables.transform(row.entrySet(), new Function<Map.Entry<String, Object>, String>() {
                            @Override
                            public String apply(Entry<String, Object> input) {
                                // 默认直接处理成字符串
                                Object val = input.getValue();
                                if (null == val) {
                                    return "";
                                }
                                if ("commName".equals(input.getKey())) {
                                    return val.toString().replace("\n", "").replace("\r", "");
                                }
                                return val.toString();
                            }
                        }));
                    }
                }, limit == null ? -1 : limit);
    }

    /**
     * 批量入库
     * 
     * @author 13071602
     * 
     * @param <T>
     */
    private class BatchUpdateAction<T> implements Action<T> {

        private String sqlId;

        public BatchUpdateAction(String sqlId) {
            this.sqlId = sqlId;
        }

        @SuppressWarnings("unchecked")
        @Override
        public void action(T[] objs) {
            Map<String, Object>[] batchValues = Iterables
                    .toArray(Iterables.transform(Lists.newArrayList(objs), new Function<T, Map<String, Object>>() {
                        @Override
                        public Map<String, Object> apply(T input) {
                            return new BeanMap(input);
                        }
                    }), Map.class);
            dalClient.batchUpdate(sqlId, batchValues);
        }
    }

    @Override
    public void downloadNoClusterModel(String remoteDirectory, String date, String fileName, boolean isMuti)
            throws IOException {
        final LocalDate localDate = new TodaySupplier(date).get();
        ftpSynService.downloadBIFile(remoteDirectory, fileName, localDate, new SimpleContextWithDefinition(
                ModelCommodityClusterBean.class, "|@|\n",
                new DefaultLineMapper<ModelCommodityClusterBean>(ModelCommodityClusterBean.class,
                        new String[] { "disCode", "disName", "orgCode", "orgName", "cateCode", "cateName",
                                "branch4code", "branch9code", "branchName", "commCode", "commName", "storeCode" },
                        "|$|", new PropertySetter<ModelCommodityClusterBean>()),
                null, new BatchUpdateAction<ModelCommodityClusterBean>(
                        "MODEL_COMMODITY_CLUSTER.INSERT_MODEL_COMM_NOCLUSTER")),
                isMuti);
    }

    private class PropertySetter<T> extends AbstractPropertySetter<T> {
        @Override
        protected Optional<Object> property(String name, String value) throws Exception {
            if (("monthSaleNum".equals(name) || "storageNum".equals(name)) && StringUtils.isNotBlank(value)
                    && value.contains(".")) {
                value = value.substring(0, value.indexOf("."));
                return Optional.of((Object) Integer.valueOf(value));
            }
            return Optional.absent();
        }
    }

    private class SaleModelPropertySetter<T> extends AbstractPropertySetter<T> {
        @Override
        protected Optional<Object> property(String name, String value) throws Exception {
            if ("storeCode".equals(name)) {
                if (STORE_PATTERN.matcher(value).matches()) {
                    String storeCode = value.replaceFirst(value.substring(0, 1), STORE_MAP.get(value.substring(0, 1)));
                    return Optional.of((Object) storeCode);
                } else {
                    return Optional.of((Object) value);
                }
            }
            if ("storageNum".equals(name)) {
                String storageNum = value.substring(0, value.indexOf("."));
                return Optional.of((Object) Integer.valueOf(storageNum));
            }
            if ("commCode".equals(name)) {
                if (value.length() > 9) {
                    String commCode = value.substring(9, value.length());
                    return Optional.of((Object) commCode);
                } else {
                    return Optional.of((Object) value);
                }
            }
            return Optional.absent();
        }
    }

    private class BIModelValidityCleanService<T extends ModelValidityBean> implements BIDataCleanService<T> {
        @Override
        public boolean clean(T obj) {
            if (obj.getMonthSaleNum() != null) {
                int saleNum = obj.getMonthSaleNum();
                Calendar c = Calendar.getInstance();
                c.setTime(DateUtils.getDateByStr(obj.getStatisDate(), "yyyyMMdd"));
                int month = c.get(Calendar.MONTH) + 1;
                switch (month) {
                    case 1:
                        obj.setSaleCount1(saleNum);
                        break;
                    case 2:
                        obj.setSaleCount2(saleNum);
                        break;
                    case 3:
                        obj.setSaleCount3(saleNum);
                        break;
                    case 4:
                        obj.setSaleCount4(saleNum);
                        break;
                    case 5:
                        obj.setSaleCount5(saleNum);
                        break;
                    case 6:
                        obj.setSaleCount6(saleNum);
                        break;
                    case 7:
                        obj.setSaleCount7(saleNum);
                        break;
                    case 8:
                        obj.setSaleCount8(saleNum);
                        break;
                    case 9:
                        obj.setSaleCount9(saleNum);
                        break;
                    case 10:
                        obj.setSaleCount10(saleNum);
                        break;
                    case 11:
                        obj.setSaleCount11(saleNum);
                        break;
                    case 12:
                        obj.setSaleCount12(saleNum);
                        break;
                    default:
                        LOGGER.error("month error");
                }
            }
            return true;
        }

    }

    private class BIModelSaleCleanService<T extends ModelFinanceListBean> implements BIDataCleanService<T> {
        @Override
        public boolean clean(T obj) {
            obj.setStorageCode(ModelConstant.MODEL_LIB);
            // 增加判断逻辑 门店编码取哪个字段
            if (!obj.getStoreCodeFlag().startsWith("D")) {
                obj.setStoreCode(obj.getStoreCodeFlag());
            }
            String storeCode = obj.getStoreCode();
            StoreInfo store = storeInfoService.queryStoreByCode(storeCode);
            if (store != null) {
                obj.setStoreName(store.getStoreName());
                obj.setOrgCode(store.getSaleBranchCode());
                obj.setOrgName(store.getBranchName());
                obj.setDisCode(store.getRegionCode());
                obj.setDisName(store.getRegionName());
            }
            ModelCommodityBaseInfo comm = modelCommodityInfoService.queryCommodityBaseInfo(obj.getCommCode());
            if (comm != null) {
                obj.setBranch4code(comm.getBranch4code());
                obj.setBranch9code(comm.getBranch9code());
                obj.setBranchName(comm.getBranchName());
                obj.setCateCode(comm.getCateCode());
                obj.setCateName(comm.getCateName());
                obj.setCommName(comm.getCommName());
            }
            return true;
        }

    }

    private class BIModelSaleExptCleanService<T extends ModelFinanceStorageProblemListBean>
            implements BIDataCleanService<T> {
        @Override
        public boolean clean(T obj) {
            if (StringUtils.isBlank(obj.getStoreName())) {
                String storeCode = obj.getStoreCode();
                StoreInfo store = storeInfoService.queryStoreByCode(storeCode);
                if (store != null) {
                    obj.setStoreName(store.getStoreName());
                    obj.setOrgCode(store.getSaleBranchCode());
                    obj.setOrgName(store.getBranchName());
                    obj.setDisCode(store.getRegionCode());
                    obj.setDisName(store.getRegionName());
                }
            }
            if (StringUtils.isBlank(obj.getCommName())) {
                ModelCommodityBaseInfo comm = modelCommodityInfoService.queryCommodityBaseInfo(obj.getCommCode());
                if (comm != null) {
                    obj.setBranch4code(comm.getBranch4code());
                    obj.setBranch9code(comm.getBranch9code());
                    obj.setBranchName(comm.getBranchName());
                    obj.setCateCode(comm.getCateCode());
                    obj.setCateName(comm.getCateName());
                    obj.setCommName(comm.getCommName());
                }
            }
            return true;
        }

    }

    @Override
    public void downloadSaleModelExpt(String remoteDirectory, String date, String fileName, boolean isMuti)
            throws IOException {
        final LocalDate localDate = new TodaySupplier(date).get();
        ftpSynService.downloadBIFile(remoteDirectory, fileName, localDate, new SimpleContextWithDefinition(
                ModelFinanceStorageProblemListBean.class, "|@|\n",
                new DefaultLineMapper<ModelFinanceStorageProblemListBean>(ModelFinanceStorageProblemListBean.class,
                        new String[] { "disCode", "disName", "orgCode", "orgName", "storeCode", "storeName", "cateCode",
                                "cateName", "branch4code", "branch9code", "branchName", "commCode", "commName",
                                "attribute", "storageNum", "checkNum", "storageCode", "storageFlag" },
                        "|$|", new PropertySetter<ModelFinanceStorageProblemListBean>()),
                new BIModelSaleExptCleanService<ModelFinanceStorageProblemListBean>(),
                new BatchUpdateAction<ModelFinanceStorageProblemListBean>("MODEL_MAIN_LIST.INSERT_MODEL_SALE_EXPT")),
                isMuti);
    }

    @Override
    public void downloadModelValidity(String remoteDirectory, String date, String fileName, boolean isMuti)
            throws IOException {
        final LocalDate localDate = new TodaySupplier(date).get();
        ftpSynService.downloadBIFile(remoteDirectory, fileName, localDate,
                new SimpleContextWithDefinition(ModelValidityBean.class, "|@|\n",
                        new DefaultLineMapper<ModelValidityBean>(ModelValidityBean.class,
                                new String[] { "disCode", "disName", "orgCode", "orgName", "storeCode", "storeName",
                                        "storeType", "cateCode", "cateName", "branch4code", "branch9code", "branchName",
                                        "commCode", "commName", "attribute", "commNum", "monthSaleNum", "statisDate" },
                                "|$|", new PropertySetter<ModelValidityBean>()),
                        new BIModelValidityCleanService<ModelValidityBean>(),
                        new BatchUpdateAction<ModelValidityBean>("MODEL_MAIN_LIST.INSERT_MODEL_VALIDITY")),
                isMuti);
    }

    @Override
    public void downloadSaleModel(String remoteDirectory, String date) throws IOException {
        final LocalDate localDate = new TodaySupplier(date).get();
        modelFinFtpService.downloadFile(remoteDirectory, localDate, new SimpleContextWithDefinition(
                ModelFinanceListBean.class, "\n",
                new DefaultLineMapper<ModelFinanceListBean>(ModelFinanceListBean.class,
                        new String[] { "commCode", "storeCodeFlag", "storeCode", "serialNo", "column2", "column3",
                                "storageNum" },
                        ",", new SaleModelPropertySetter<ModelFinanceListBean>()),
                new BIModelSaleCleanService<ModelFinanceListBean>(),
                new BatchUpdateAction<ModelFinanceListBean>("MODEL_MAIN_LIST.INSERT_MODEL_SALE")));

    }

    @Override
    public void downloadSaleModelInit(String remoteDirectory, String date) throws IOException {
        final LocalDate localDate = new TodaySupplier(date).get();
        modelFinInitFtpService.downloadFile(remoteDirectory, localDate, new SimpleContextWithDefinition(
                ModelFinanceListBean.class, "\n",
                new DefaultLineMapper<ModelFinanceListBean>(ModelFinanceListBean.class,
                        new String[] { "commCode", "storeCodeFlag", "storeCode", "serialNo", "column2", "column3",
                                "storageNum" },
                        ",", new SaleModelPropertySetter<ModelFinanceListBean>()),
                new BIModelSaleCleanService<ModelFinanceListBean>(),
                new BatchUpdateAction<ModelFinanceListBean>("MODEL_MAIN_LIST.INSERT_MODEL_SALE")));
    }

    
    /**
     * op 是否跳过月初限制
     */
    @Override
    public void exportCsvModelAll(Boolean op) throws IOException {

        LOGGER.info("exportCsvModelAll,begin");
        String exportCsvModelAll_flag = SCMConfigUtil.getConfig("exportCsvModelAll_flag","1");
        if("1".equals(exportCsvModelAll_flag)){
            if(DateUtils.isFirstDayByMonth() || (op != null && op == true)){
                int pageSize = getExptCSVLimit();
                int pageNo = 1;
                SQLIterator sqli = null ;
                try {
                    sqli = new SQLIterator(dataSource, selectSqls.get("queryByStoreCodeAll"));
                    
                    List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
                    while (sqli.hasNext()) {
                        
                        list.add(sqli.next());
                        if(list.size() >= pageSize){
                            createCsvForModelIndex(list,pageNo);
                            list.clear();
                            pageNo ++;
                        }
                    }
                    
                    if(CollectionUtils.isNotEmpty(list)){
                        createCsvForModelIndex(list,pageNo);
                    }
                } catch (SQLException e) {
                    LOGGER.error("exportCsvModelAll pageNo:"+ pageNo,e);
                } finally {
                    if(sqli != null){
                        if (sqli instanceof Closeable) {
                            ((Closeable) sqli).close();
                        }
                    }
                }
            }else{
                LOGGER.warn("exportCsvModelAll is not the right time ,begin");
            }
        }else{
            LOGGER.warn("exportCsvModelAll is closed ,begin");
        }

    }

    private void createCsvForModelIndex(List<Map<String, Object>> list, int pageNo) {
        // 标题
        String[] titles = new String[] { "大区编码", "大区名称", "分公司编码", "分公司名称", "门店编码", "门店名称", "品类编码", "品类名称",
                "品牌编码", "品牌名称", "商品编码", "商品名称", "库位", "样机属性", "样机数量", "状态" };
            List<List<String>> data = null;
            if (CollectionUtils.isNotEmpty(list)) {
                // list转换-保留要插入到csv中的字段
                data = com.google.common.collect.Lists.transform(list, new Function<Map<String, Object>, List<String>>() {
                    @Override
                    public List<String> apply(Map<String, Object> bean) {
                        List<String> msg = new ArrayList<String>();
                        msg.add(String.valueOf( bean.get( "disCode")));
                        msg.add(String.valueOf(bean.get( "disName")));
                        msg.add(String.valueOf(bean.get( "orgCode")));
                        msg.add(String.valueOf(bean.get( "orgName")));
                        msg.add(String.valueOf(bean.get( "storeCode")));
                        msg.add(String.valueOf(bean.get( "storeName")));
                        
                        
                        msg.add(String.valueOf(bean.get( "cateCode")));
                        msg.add(String.valueOf(bean.get( "cateName")));
                        msg.add(String.valueOf(bean.get( "branch9Code")));
                        msg.add(String.valueOf(bean.get( "branchName")));
                        msg.add(String.valueOf(bean.get( "commCode")));
                        msg.add(String.valueOf(bean.get( "commName")));
                        msg.add(String.valueOf(bean.get( "storageCode")));
                        
                        msg.add(String.valueOf(bean.get( "attribute")));
                        msg.add(String.valueOf(bean.get( "commNum")));
                    
                        msg.add(String.valueOf(bean.get( "newFlag")));
                        return msg;
                    }
                });

            }
            try {
                String lastMonth = DateUtils.getLastMonth();
                String fileName = "modelList-"+lastMonth + "-" + pageNo +"-"+ new Date().getTime() + "@";  ;
                String downLoadUrl = exportFileUtil.createCsvFileAndSendEmail(fileName, titles, data, "样机监控",
                        ExportConstants.OSSFileParams.FILE_CYCLE_TIME_ONE_YEAR);
                LOGGER.info("createCsvForModelIndex fileName:{},downLoadUrl:{}",fileName,downLoadUrl);
                if(StringUtils.isNotBlank(downLoadUrl)){
                    int result = modelManageDaoService.inserModelMainHis(lastMonth,pageNo,downLoadUrl);
                    if(result <0){
                        LOGGER.error("createCsvForModelIndex error for lastMonth:{},pageNo:{},downLoadUrl:{}",lastMonth,pageNo,downLoadUrl);
                    }
                }
            } catch (Exception e) {
                LOGGER.error("createCsvForModelIndex failed.", e);
            }
    }
    
    private int getExptCSVLimit() {
        String limit = SCMConfigUtil.getConfig(ConfigConstants.MODEL_MANAGE_EXPORT_CSV_SIZE,
                ConfigConstants.DEFAULT_MODEL_MANAGE_EXPORT_CSV_SIZE);
        return Integer.valueOf(limit).intValue();
    }
}
